import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Injectable, OnDestroy, OnInit } from '@angular/core';
import { of, Subject } from 'rxjs';
import { delay, startWith, takeUntil } from 'rxjs/operators';
import { uniqueId as _uniqueId, filter as _filter } from 'lodash';
import { FilterType, TransferColumnItem } from '@iux/live/transfer/transfer.interface';

interface DemoUser {
  id: string;
  name: string;
  age: number;
  color: string;
  random: number;
  expand: boolean;
  disabled?: boolean;
}

@Injectable()
export class UserService {
  length = 50;
  users: DemoUser[] = [];

  constructor() {
    this.users = this.initUser();
  }

  getUsers(data: { [key: string]: any }) {
    let { users } = this;
    let total = users.length;
    const { filters, pageIndex, pageSize } = data,
      startIndex = pageIndex * pageSize,
      endIndex = (pageIndex + 1) * pageSize;

    // 模拟异步过滤
    if (filters) {
      for (const key of Object.keys(filters)) {
        if (key === 'name') {
          users = _filter(users, item => item.name.includes(filters[key]));
        }
      }
      total = users.length;
    }

    users = users.slice(startIndex, endIndex);

    return of({ users, total }).pipe(delay(300));
  }

  initUser() {
    const colors = ['red', 'blue', 'green', 'orange'];
    const users = Array.from({ length: this.length }).map((item, key) => ({
      id: _uniqueId('uid'),
      key: _uniqueId('uid'),
      name: `user${key}`,
      age: 10 + key,
      color: colors[parseInt(`${Math.random() * 100}`, 10) % colors.length],
      random: parseInt(`${Math.random() * 100}`, 10),
      expand: false,
      disabled: key % 5 === 0,
    }));
    return users;
  }
}

const defaultColumns: TransferColumnItem[] = [
  {
    key: 'id',
    label: 'ID',
    disabled: true,
    isHidden: true,
    hidden: true,
  },
  {
    key: 'name',
    label: 'Name',
    disabled: true,
    isHidden: false,
    filterType: FilterType.SEARCH,
  },
  {
    key: 'color',
    label: 'Color',
    width: '100px',
    disabled: false,
    isHidden: false,
  },
  {
    key: 'age',
    label: 'Age',
    disabled: false,
    isHidden: false,
  },
  {
    key: 'random',
    label: 'Random',
    disabled: false,
    isHidden: false,
  },
];

@Component({
  selector: 'app-async',
  templateUrl: './async.component.html',
  providers: [UserService],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AsyncComponent implements OnInit, OnDestroy {
  source: { cols: TransferColumnItem[]; total: number; data: DemoUser[]; selection: DemoUser[] } = {
    cols: [],
    total: 0,
    data: [],
    selection: [],
  };
  target: { cols: TransferColumnItem[] } = { cols: [] };

  pageSize = 10;
  pageIndex = 0;
  init = true;

  params: { [key: string]: any } = { pageSize: this.pageSize, pageIndex: this.pageIndex };
  params$ = new Subject<{ [key: string]: any }>();

  destroy$ = new Subject<void>();

  constructor(private service: UserService, private cdr: ChangeDetectorRef) {}

  ngOnInit() {
    this.initColumns();
    this.initAsyncData();
  }

  ngOnDestroy(): void {
    this.destroy$.next();
    this.destroy$.complete();
  }

  initColumns() {
    this.source.cols = [...defaultColumns];
    this.target.cols = [...defaultColumns];
  }

  initAsyncData() {
    this.params$.pipe(startWith(this.params), takeUntil(this.destroy$)).subscribe(res => {
      this.service.getUsers(res).subscribe((data: { users: DemoUser[]; total: number }) => {
        const { users, total } = data;
        this.source.data = users;
        this.source.total = total;

        if (users?.length && this.init) {
          this.source.selection = [users[0]];
          this.init = false;
        }

        this.cdr.markForCheck();
      });
    });
  }

  stateChange(source: { belong: string; params: any }) {
    console.log('stateChange:', source);
    const { belong } = source;

    if (belong === 'target') {
      return;
    }

    let { params = {} } = source;

    if (params.paginator) {
      params = { ...params, ...params.paginator };
    }

    if (params.filters) {
      params = { ...params, filters: params.filters };
    }

    this.updateParams(params);
  }

  updateParams(data) {
    this.params$.next((this.params = { ...this.params, ...data }));
  }

  change(e) {
    console.log('transferChange:', e);
  }
}
